<?php
#
#
# Copyright TEDECO, 2009. http://tedeco.fi.upm.es
#
# This file is part of kumenya.
#
# Kumenya is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Kumenya is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
#
#
#
?>
<?php	
class DBManager
{
	const SERVER = 'localhost';
	const USER = 'kumenyaapp';
	const PASSWORD = 'EfJ7i49c3v11';
	const DEFAULTDB = '????????';
	const LibraryDB = 'kumenya_library';
	const RegistrationDB = 'kumenya_registration';
	const AccountancyDB = 'kumenya_accountancy';

    // LINK TO THE DB
    private $link;
    
    private $error;
    private $message;

	// Object->ClassMember;
	// Allows the class members to access
	// using the same syntax of the Object members
	private function __get($name) {
		return constant("self::$name");
	}

	// GetLink ()
	// Returns the link to the DB
	private function GetLink () {
		if (isset($this->link)) {
		return $this->link;
		}
		else
			return FALSE;
	}

	// GetError ()
	// Returns the error with the DB
	public function GetError () {
		return $this->error;
	}

	// GetResult ()
	// Returns the rresult message with the DB
	public function GetResult () {
		return $this->message;
	}
	
	// GetServer ()
	// Returns the server of the DB
	private function GetServer () {
		return self::SERVER;
	}

	// GetUser ()
	// Returns the DB user
	private function GetUser () {
		return self::USER;
	}
	
	// GetPassword ()
	// Returns the DB password
	private function GetPassword () {
		return self::PASSWORD;
	}
	
	// EstablishLink ()
	// Establish the link with the DB
	private function EstablishLink ($link) {
		$this->link = $link;
	}
	
    // Connect ()
    // Establish a link with the DB
	private function Connect ($DateBase = self::DEFAULTDB) {	
		switch ($DateBase) {
			case self::LibraryDB:
				$this->EstablishLink (mysqli_connect ($this->GetServer (), $this->GetUser(), $this->GetPassword(), self::LibraryDB));
				break;
			case self::RegistrationDB:
				$this->EstablishLink (mysqli_connect ($this->GetServer (), $this->GetUser(), $this->GetPassword(), self::RegistrationDB));
				break;			
			case self::AccountancyDB:
				$this->EstablishLink (mysqli_connect ($this->GetServer (), $this->GetUser(), $this->GetPassword(), self::AccountancyDB));
				break;			
		}
		return $this->GetLink ();
	}

	// Disconnect ()
	// Remove the link to the database
	private function Disconnect () {
//		return @odbc_close($this->GetLink());
		return @mysqli_close($this->GetLink());
	}
	
	// SendQuery (querySQL)
	// Make a query to the database
	private function SendQuery ($SQLquery) {
//		return odbc_exec ($this->GetLink(), $SQLquery);
		return mysqli_query($this->GetLink(), $SQLquery);
	}

	// ReadData (querySQL)
	// Read a new row of results
	private function ReadData ($outcome, $associative = TRUE) {
		if ($associative)
			return mysqli_fetch_assoc($outcome);
		else
			return mysqli_fetch_row($outcome);
//		return odbc_fetch_row ($outcome);
	}

	// GetField (row, field)
	// Get a cell from a row of a query result 
	private function GetField ($row, $field) {
		return $row[$field];
	}

	// RowsNumber (outcome)
	// Get the number of rows of a result
	private function RowsNumber ($outcome) {
//		return odbc_num_rows ($outcome);
		return mysqli_num_rows ($outcome);
	}

	// ColumnsNumber (outcome)
	// Get the number of culumns of a result
	private function ColumnsNumber ($outcome) {
//		return odbc_num_fields ($outcome);
		return mysqli_num_fields ($outcome);
	}

	// ColumnName (outcome, i)
	private function ColumnName ($outcome, $number) {
//		return odbc_field_name ($outcome, $number);
		$column = mysqli_fetch_field_direct($outcome, $number);
		return $column->name;
	}

	// ErrorMessage ()
	// Return the error message 
	private function ErrorMessage () {
		$link = $this->GetLink ();			
		if ($link)
//			$this->error = odbc_errormsg ($link);
			$this->error = mysqli_error($link);
		else
//			$this->error = odbc_errormsg ();
			$this->error = mysqli_connect_error();
	}

	private function SelectDataBase ($scope) {
		if ($scope)
			switch ($scope) {
				case Library: 
					return $this->LibraryDB;
				case Enrollment: 
					return $this->RegistrationDB;
				case Accountancy: 
					return $this->AccountancyDB;
				case self::LibraryDB:
				case self::RegistrationDB:
				case self::AccountancyDB:
					return $scope;
				default:
					return FALSE;
	 		}
 	}

	// Get an entry to the configuration table
	public function Configuration ($input = FALSE) {
		if ($input) {
			$BD = $this->SelectDataBase(Library);

			// INPUT VECTOR
			if (is_array($input)) {
				$sql = "SELECT AttributeName, Value FROM configuration WHERE ";
				foreach ($input as $attribute => $value)
					$sql .= "AttributeName='$attribute' OR ";
	
				$sql = chop($sql," OR ");
			}
			// ONLY ENTRY
			else
				$sql = "SELECT AttributeName, Value FROM configuration WHERE AttributeName='$input'";

//echo "CONF: $sql<br/>";

			// CONNECTED
			if ($this->Connect($BD)) {
				// PERFORMING THE QUERY
				$outcome = $this->SendQuery($sql);
				// CHECK THE RESULT
				if ($outcome) {
					$keysNumber = $this->RowsNumber($outcome);
					if ($keysNumber > 0) {
						$configuration = array();
						
						// READ RESULT
						while ($row = $this->ReadData ($outcome)) {
							$name = $row[AttributeName];
							$value = $row[Value];
							$configuration[$name] = $value;
						}
	
						// DISCONNECTED
						$this->Disconnect ();
						return $configuration;
					}
				}
				// ERROR IN THE EXECUTION OF THE SQL QUERY
				else {
					$this->ErrorMessage ();
					$this->Disconnect ();
					return FALSE;
				}
			}			
			// CONNECTION ERROR
			else {
				$this->Error();
				return FALSE;
			}
		}
		return FALSE;
	}


	// Get the external keys of a table
	private function ExternalKeys ($tableName, $scope) {
		$BD = $this->SelectDataBase($scope);

		$sql = "SELECT * FROM externalkeys WHERE Table='$tableName'";

		if ($this->Connect($BD)) {
			$outcome = $this->SendQuery($sql);
			if ($outcome) {
				$keysNumber = $this->RowsNumber($outcome);
				if ($keysNumber > 0) {
					$keys = array();
					$fields = array();
	//				while ($this->ReadData ($outcome)) {
	//					$column = $this->GetField($outcome, Column);
	//					$purpose = $this->GetField($outcome, ReferencedTable );
	//					$scope = $this->GetField($outcome, Scope);
	//					$key = $this->GetField($outcome, InternalValue);
	//					$value = $this->GetField($outcome, ShownValue);
	
					while ($row = $this->ReadData ($outcome)) {
						$column = $row[Column];
						$purpose = $row[ReferencedTable ];
						$scope = $row[Scope];
						$key = $row[InternalValue];
						$value = $row[ShownValue];
		
						// READ REFERENCE OF THE EXTERNAL KEY
						$sql = "SELECT $key, $value FROM $scope.$purpose";
						$outcome2 = $this->SendQuery($sql);
						if ($outcome2) {
							$values = "REF ";
							$valuesNumber = $this->RowsNumber($outcome2);
							if ($valuesNumber > 0)
	//							while ($this->ReadData ($outcome2)) {
	//								$key2 = $this->GetField($outcome2, $key);
	//								$value2 = $this->GetField($outcome2, $value);
								while ($row2 = $this->ReadData ($outcome2)) {
									$key2 = $row2[$key];
									$value2 = $row2[$value];
									if ((!empty($value2)) && !empty($key2))
										$values .= "$key2%$value2%";
								}
							$values = chop($values,"%");
		
							$fields[$column] = $values;
						}
						else {
							$this->ErrorMessage ();
							$this->Disconnect ();
							return FALSE;
						}
					}					

					return $fields;
				}
			}
		}
		else {
			$this->Error();
			return FALSE;
		}
	}

	private function ValuesList ($references) {
		$outcome = array();
		foreach ($references as $name => $value) {
			$value = strtok ($value," ");
			$valueList = array();
			$key = 1;
			while ($value && $key) {
				$key = strtok ("%");
				if (!empty($key)) {
					$value = strtok ("%");
					if (!empty($value))
						$valueList[$key] = $value;
				}
			}
			$outcome[$name] = $valueList;
		}
		return $outcome;		
	}
	
	public function MultipleTablesFields ($procedureName, $scope, $originTable, $specificTable = FALSE) {
		$BD = $this->SelectDataBase($scope);

		if ($this->Connect($BD)) {
			$sql = "CALL $procedureName ()";
			$outcome = $this->SendQuery($sql);
			if ($outcome) {
				$tables = array();
				while ($row = $this->ReadData ($outcome)) {
					$tableName = $row["table_name"];
					if (isset($tables[$tableName]))
						$tables[$tableName][Columns][] = $row["column_name"];
					else {
						$table = array();					
						$table[Scope] = $row["table_schema"];
						$table[Columns] = array();
						$table[Columns][] = $row["column_name"];						
						$tables[$tableName] = $table;
					}
				}
//				$this->Disconnect ();

				$fields = array();
				$fields[Type] = array();
				$fields[Null] = array();
				$type = array();
				$null = array();
				$new = array();
				
				if (!$specificTable) {
					foreach ($tables as $tableName => $table) {
						$scope = $table[Scope];
						$columns = $table[Columns];
						if ($tableName != $originTable)
							$new = $this->TableFields ($tableName,$scope,$columns, TRUE);
						else
							$new = $this->TableFields ($tableName,$scope,$columns);						

						if ($new) {
							$type = $new[Type];
							$null = $new[Null];
							$fields[Type] = $fields[Type] + $type;
							$fields[Null] = $fields[Null] + $null;
						}
						else
							return FALSE; 
					}
				}
				else {
					$table = $tables[$specificTable];
					$scope = $table[Scope];
					$columns = $table[Columns];
					$new = $this->TableFields ($specificTable,$scope,$columns, TRUE);
					$type = $new[Type];
					$null = $new[Null];
					if ($new) {
						$fields[Type] = $type;
						$fields[Null] = $null;
					}
				}
				return $fields;
			}
			else {	
				$this->ErrorMessage ();
				$this->Disconnect ();
				return FALSE;
			}
		}
		else {
			$this->ErrorMessage ();
			$this->Disconnect ();
			return FALSE;
		}
	}
	
	// TableFields (name, scope)
	// RETURNS THE FIELDS FROM THE TABLE 'NAME'
	public function TableFields ($tableName, $scope, $selection = false, $multiple = false) {
		$BD = $this->SelectDataBase($scope);
		
		// READ FIELDS FROM THE TABLE
		$sql = "SHOW COLUMNS FROM $tableName";
			if ($this->Connect($BD)) {
			$outcome = $this->SendQuery($sql);
			if ($outcome) {
				$columns = array();
				$fields = array();
				$nulls = array();
				$keysNumber = $this->RowsNumber($outcome);
				if ($keysNumber > 0)
//					while ($this->ReadData ($outcome)) {
//						$field = $this->GetField($outcome, Field);
//						$type = $this->GetField($outcome, Type);
//						$null = $this->GetField($outcome, Null);
//						$key = $this->GetField($outcome, Key);
					while ($row = $this->ReadData ($outcome)) {
						$field = $row[Field];
						if (!$selection || in_array($field, $selection)) {
							$type = $row[Type];
							$null = $row[Null];
							$key = $row[Key];							
							if ($multiple && $field == Uid && $type == UID)
								$fieldName = $field . $tableName;
							else 
								$fieldName = $field;
							$fields[$fieldName] = $type;
							$nulls[$fieldName] = $null;
							if ($key == PrimaryKey)
								$nulls[$fieldName] = YES;
						}
					}

				// READ THE EXTERNAL KEYS FROM THE TABLE
				$sql = "SELECT * FROM externalkeys WHERE Table='$tableName'";
				$outcome = $this->SendQuery($sql);
				if ($outcome) {
					$keysNumber = $this->RowsNumber($outcome);
					if ($keysNumber > 0) {
						$keys = array();
//						while ($this->ReadData ($outcome)) {
//							$column = $this->GetField($outcome, Column);
//							$purpose = $this->GetField($outcome, ReferencedTable );
//							$scope = $this->GetField($outcome, Scope);
//							$key = $this->GetField($outcome, InternalValue);
//							$value = $this->GetField($outcome, ShownValue);
						while ($row = $this->ReadData ($outcome)) {
							$column = $row[Column];
							$purpose = $row[ReferencedTable ];
							$scopeRef = $row[Scope];
							$key = $row[InternalValue];							
							$value = $row[ShownValue];
							// READ REFERENCE OF THE EXTERNAL KEY
							if (isset($fields[$column])) {
								$BDRef = $this->SelectDataBase($scopeRef);							
								$sql = "SELECT $key, $value FROM $BDRef.$purpose";								
								$outcome2 = $this->SendQuery($sql);
								if ($outcome2) {
									$values = "REF ";
									if ($nulls[$column] == YES)
										$values .= " % %";									
									$valuesNumber = $this->RowsNumber($outcome2);
									if ($valuesNumber > 0)
//										while ($this->ReadData ($outcome2)) {
//											$key2 = $this->GetField($outcome2, $key);
//											$value2 = $this->GetField($outcome2, $value);
										while ($row2 = $this->ReadData ($outcome2)) {
											$key2 = $row2[$key];
											$value2 = $row2[$value];
											if ((!empty($value2)) && !empty($key2))
												$values .= "$key2%$value2%";
										}
									$values = chop($values,"%");

									$fields[$column] = $values;
								}
								else {
									$this->ErrorMessage ();
									$this->Disconnect ();
									return FALSE;
								}
							}
						}
					}	

					$this->Disconnect ();
					$columns[Type] = $this->Fields($fields);
					$columns[Null] = $nulls;
					return $columns;
				}
				else {
					// THE TABLE DOES NOT CONTAIN EXTERNAL KEYS
					$this->Disconnect ();
					return $this->Fields($fields);
				}
			}
			else {
				$this->ErrorMessage ();
				$this->Disconnect ();
				return FALSE;
			}
		}
		else
			$this->ErrorMessage ();
		return FALSE;
	}
		
	
	function Fields ($dBFields, $values = FALSE) {
		$fields = array();
		foreach ($dBFields as $name => $type) {
			switch ($type) {
				// Identifier
				case UID:
					$fields[$name] = UID;
					break;
				
				// Date			
				case Date:	
					$fields[$name] = Date;
					break;

				// Integer			
				case Integer: 					
					$fields[$name] = Integer;
					break;

				// Year			
				case Year:
					$fields[$name] = Year;
					break;

				case Real:
					$fields[$name] = Real;
					break;

				case Boolean:
					$fields[$name] = Boolean;
					break;
					
				default:
					// Enumerated
					
//////////////////////////////
// IT'S MISSING THE POSSIBILITY THAT THE ENUMERATED FIELDS COULD BE NULL
//////////////////////////////
					
					if (substr($type,0,4) == 'enum') {
						$fields[$name] = $type;
					}
					
					// Reference the table
					else if (substr($type,0,4) == 'REF ') {
						$fields[$name] = $type;
					}

					
					// Chain
					else {
						$length = substr($type,8);
						$length = chop ($length,")");
						$fields[$name] = Chain . $length;
					}
					break;
			}
		}
		return $fields;
	}
	
	public function ExecuteProcedureReport ($procedureName, $scope, $values = array()) {
		// CHECK THAT THE PROCEDURE EXIST IN THE DATABASE
		// ..

		// READ PROCEDURE PARAMETERS
		$sql = "SELECT Name,Type FROM ".ParametersTable." WHERE UidProc = (SELECT Uid FROM ".ProceduresTable." WHERE Name='$procedureName') ORDER BY Orden ASC";
		if ($this->Connect($this->LibraryDB)) {
			$outcome = $this->SendQuery($sql);
			if ($outcome) {			
				$parametersNumber = $this->RowsNumber($outcome);
//echo "$sql<br/>";
				if ($parametersNumber > 0)
//					while ($this->ReadData ($outcome))
//						$parameters[$this->GetField($outcome, "Name")] = $this->GetField($outcome, "Type");
					while ($row = $this->ReadData ($outcome))
						$parameters[$row["Name"]] = $row["Type"];
				$sql = "CALL $procedureName (";

				$outputParametersNumber = 0;
				$outputParameters = array();

				foreach ($parameters as $name => $type) {
					if (($type == Input) || ($type == InputOutput)) {
						if (empty($values[$name]) && $values[$name]!='0')
							$sql .= 'NULL,';
						else if ($values[$name]=='0')
							$sql .= "'".$values[$name]."',";
						else
							$sql .= "'".$values[$name]."',";
					}
					else {
						$sql .= '@'.$name.',';
						$outputParametersNumber++;
						$outputParameters[$outputParametersNumber] = $name;						
					}
				}
				$sql = chop($sql,',');
				$sql .= ')';
//echo "INFO: $sql<br/>";

				$outcome = $this->SendQuery($sql);
				if ($outcome) {
					return $this->ReadProcedureResultReport ($outcome, $outputParametersNumber, $outputParameters, $scope);
				}
				else {
					$this->ErrorMessage ();
					$this->Disconnect();
				}
			}
			else {
				$this->ErrorMessage ();
				$this->Disconnect();
			}
		}
		$this->ErrorMessage ();
		return FALSE;
	}

	private function ReadProcedureResultReport ($outcome, $outputParametersNumber, $outputParameters, $scope) {			
		if ($row = $this->ReadData ($outcome, FALSE)) {
			$result = $this->GetField($row, 0);
			if (!$result) {
/*				$message = utf8_decode ($this->GetField($row, 1));
				$message = mb_convert_encoding ($message, 'ISO-8859-1');
*/				$message = $this->GetField($row, 1);
//				$message = mb_convert_encoding ($message, 'ISO-8859-1', 'UTF-8');
				$this->error = $message;
				return FALSE;
			}

			$procedureResult = array();
			for ($i = 1; $i <= 2; $i++) {
//				$message = utf8_decode ($this->GetField($row, $i));
//				$message = mb_convert_encoding ($message, 'ISO-8859-1', 'UTF-8');
				$message = $this->GetField($row, $i);
//				$message = mb_convert_encoding ($message, 'ISO-8859-1', 'UTF-8');
				$procedureResult[$outputParameters[$i+1]] = $message;
			}
			

			$sql = $this->GetField($row, 3);
//echo "SQL: $sql<br/>";
			
			$this->Disconnect();
			
			$BD = $this->SelectDataBase($scope);

			if (!$this->Connect($BD)) {
				$this->ErrorMessage();
				return FALSE;
			}
			$consult = $this->SendQuery($sql);
			if ($consult) {			
				$outcomesnumber = $this->RowsNumber($consult);
				$columnsNumber = $this->ColumnsNumber($consult);
				$table = array();
				if ($outcomesnumber > 0) {
					while ($resRow = $this->ReadData ($consult, FALSE)) {
						$row = array();
						for ($i = 0; $i <= $columnsNumber - 1; $i++) {
							$columnName = $this->ColumnName($consult, $i);
							$columnValue = $resRow[$i];
							if (isset($columns[$columnName]))
								$row[$columnName] = $columns[$columnName][$columnValue];
							else
								$row[$columnName] = $columnValue;
						}
						$table[] = $row;
					}
				}
				$this->Disconnect();
			}
			else {
				$this->ErrorMessage();
				$this->Disconnect();
				return FALSE;
			}
			

			$procedureResult[0] = $table;
			return $procedureResult;
		}
		return FALSE;
	}

	public function ExecuteProcedure ($procedureName, $scope, $values = array(), $isQuery = FALSE) {
		// CHECK THAT THE PROCEDURE EXIST IN THE DATABASE
		// ..

		$BD = $this->SelectDataBase($scope);

		// READ PROCEDURE PARAMETERS
		$sql = "SELECT Name,Type FROM ".ParametersTable." WHERE UidProc = (SELECT Uid FROM ".ProceduresTable." WHERE Name='$procedureName') ORDER BY Orden ASC";
		if ($this->Connect($BD)) {
			$outcome = $this->SendQuery($sql);
			if ($outcome) {			
				$parametersNumber = $this->RowsNumber($outcome);
//echo "$sql<br/>";
				if ($parametersNumber > 0)
//					while ($this->ReadData ($outcome))
//						$parameters[$this->GetField($outcome, "Name")] = $this->GetField($outcome, "Type");
					while ($row = $this->ReadData ($outcome))
						$parameters[$row["Name"]] = $row["Type"];
				$sql = "CALL $procedureName (";

				$outputParametersNumber = 0;
				$outputParameters = array();
				foreach ($parameters as $name => $type) {
					if (($type == Input) || ($type == InputOutput)) {
						if (empty($values[$name]) && $values[$name]!='0')
							$sql .= 'NULL,';
						else if (ctype_digit($values[$name]))
							$sql .= "$values[$name],";
						else if ($values[$name]=='0')
							$sql .= "'".$values[$name]."',";
						else {
/*							if ($isQuery)		
								$usedValue = mb_convert_encoding ($values[$name], 'UTF-8', 'ISO-8859-1');
							else
*/								$usedValue = $values[$name];
//							$sql .= "'".$values[$name]."',";
							$sql .= "'".str_replace("'","&#180",$usedValue)."',";
						}
					}
					else {
						$sql .= '@'.$name.',';
						$outputParametersNumber++;
						$outputParameters[$outputParametersNumber] = $name;						
					}
				}
				$sql = chop($sql,',');
				$sql .= ')';
//echo "PROC: $sql<br/>";

				$outcome = $this->SendQuery($sql);
				if ($outcome) {
					$result = $this->ReadProcedureResult ($outcome, $outputParametersNumber, $outputParameters, $isQuery);
					$this->Disconnect();
					return $result;
				}
				else {
					$this->ErrorMessage ();
					$this->Disconnect();
				}
			}
			else {
				$this->ErrorMessage ();
				$this->Disconnect();
			}
		}
		else
			$this->ErrorMessage ();
		return FALSE;
	}

	private function ReadProcedureResult ($outcome, $outputParametersNumber, $outputParameters, $isQuery) {			
		switch ($outputParametersNumber) {
			case 1:
				if ($row = $this->ReadData ($outcome, FALSE)) {
					$result = $this->GetField($row, 0);
					return $result;
				}
				return FALSE;
			case 2:
				if ($row = $this->ReadData ($outcome, FALSE)) {
					$result = $this->GetField($row, 0);
/*					$message = utf8_decode ($this->GetField($row, 1));
					$message = utf8_decode ($message);
*/
					$message = $this->GetField($row, 1);

					if (!$isQuery) {
						$code = mb_detect_encoding ($message);
						if ($code == 'UTF-8')
							$message = mb_convert_encoding ($message,'ISO-8859-1','UTF-8');
					}
					if ($result) {
						$this->message = $message;
						return TRUE;
					}
					else
						$this->error = $message;
				}
				return FALSE;
			default:
				if ($row = $this->ReadData ($outcome, FALSE)) {
					if ($isQuery) {
						$procedureResult = array();
						for ($i = 0; $i <= $outputParametersNumber - 1; $i++)
							$procedureResult[$outputParameters[$i+1]] = $this->GetField($row, $i);
					}
					else {
						$result = $this->GetField($row, 0);
						if (!$result) {
							$error = $this->GetField($row, 1);
							$code = mb_detect_encoding ($error);
							if ($code == 'UTF-8')
								$error = mb_convert_encoding ($error,'ISO-8859-1','UTF-8');
							$this->error = $error;
//							$this->error = $this->GetField($row, 1);
							return FALSE;
						}
						$procedureResult = array();
						for ($i = 1; $i <= $outputParametersNumber - 1; $i++)
//							$procedureResult[$outputParameters[$i+1]] = mb_convert_encoding ($this->GetField($row, $i), 'ISO-8859-1', 'UTF-8');
							$procedureResult[$outputParameters[$i+1]] = $this->GetField($row, $i);
					}
					$this->message = $procedureResult;
					return $procedureResult;
				}
				return FALSE;
		}
	}

	public function SearchStatistics ($procedureName, $scope, $values = array(), $DateBase = self::DEFAULTDB) {
		// CHECK THAT THE PROCEDURE EXIST IN THE DATABASE
		// ..

		// READ PROCEDURE PARAMETERS
		$sql = "SELECT Name,Type FROM ".ParametersTable." WHERE UidProc = (SELECT Uid FROM ".ProceduresTable." WHERE Name='$procedureName') ORDER BY Orden ASC";
		if ($this->Connect($this->LibraryDB)) {
			$outcome = $this->SendQuery($sql);
			if ($outcome) {			
				$parametersNumber = $this->RowsNumber($outcome);
//echo "$sql<br/>";
				if ($parametersNumber > 0)
//					while ($this->ReadData ($outcome))
//						$parameters[$this->GetField($outcome, "Name")] = $this->GetField($outcome, "Type");
					while ($row = $this->ReadData ($outcome))
						$parameters[$row["Name"]] = $row["Type"];
				$sql = "CALL $procedureName (";

				$outputParametersNumber = 0;
				$outputParameters = array();

				foreach ($parameters as $name => $type) {
					if (($type == Input) || ($type == InputOutput)) {
						if (empty($values[$name]) && $values[$name]!='0')
							$sql .= 'NULL,';
						else if ($values[$name]=='0')
							$sql .= "'".$values[$name]."',";
						else
							$sql .= "'".$values[$name]."',";
					}
					else {
						$sql .= '@'.$name.',';
						$outputParametersNumber++;
						$outputParameters[$outputParametersNumber] = $name;						
					}
				}
				$sql = chop($sql,',');
				$sql .= ')';
//echo "STAT: $sql<br/>";

				$outcome = $this->SendQuery($sql);
				if ($outcome) {
					if ($row = $this->ReadData ($outcome, FALSE)) {
						$result = $this->GetField($row, 0);
				
						if ($result) {
							$procedureResult = array();
							for ($i = 1; $i <= $outputParametersNumber - 1; $i++)
								$consultations[$outputParameters[$i+1]] = $this->GetField($row, $i);
							$this->Disconnect();
						}
						return $this->ReadStatisticsResult ($consultations, $outputParametersNumber, $outputParameters);
					}
					else {
						$this->ErrorMessage ();
						$this->Disconnect();
					}
				}
				else {
					$this->ErrorMessage ();
					$this->Disconnect();
				}
			}
			else {
				$this->ErrorMessage ();
				$this->Disconnect();
			}
		}
		$this->ErrorMessage ();
		return FALSE;
	}

	private function ReadStatisticsResult ($consultations, $outputParametersNumber, $outputParameters) {			
		if ($this->Connect($this->LibraryDB)) {	
			foreach ($consultations as $data => $sql) {
//echo "$sql<br/>";					
				$res = $this->SendQuery($sql);
				
				if ($res) {
					if ($statistic = $this->ReadData ($res, FALSE)) {
						$statistic = $this->GetField($statistic, 0);
						$procedureResult[$data] = $statistic;
					}
				}
				else {
					$this->ErrorMessage ();
					return FALSE;
				}
				
			}
			return $procedureResult;
	
		}
		$this->ErrorMessage ();
		return FALSE;
	}

	public function SearchCriterias ($procedureName, $scope) {
		// CHECK THAT THE PROCEDURE EXIST IN THE DATABASE
		// ..


		$BD = $this->SelectDataBase($scope);
		
		$criterias = array();
		// READ PROCEDURE PARAMETERS
		$sql = "SELECT Name, ".DataType." FROM ".ParametersTable." WHERE Type='".Input."' AND UidProc = (SELECT Uid FROM ".ProceduresTable." WHERE Name='$procedureName')";
//echo "$sql<br/>";
		if ($this->Connect($BD)) {
			$outcome = $this->SendQuery($sql);
			if ($outcome) {			
				$parametersNumber = $this->RowsNumber($outcome);

				if ($parametersNumber > 0)
//					while ($this->ReadData ($outcome))
//						$criterias[$this->GetField($outcome, "Name")] = $this->GetField($outcome, DataType);
					while ($row = $this->ReadData ($outcome)) {
						$criterias[$row["Name"]] = $row[DataType];
						if (substr ($row[DataType], 0, 3) == "ref") {
							$table = substr ($row[DataType], 4);
							$references = $this->ExternalKeys ($table, $scope);
							$criterias[$row["Name"]] = $references[$row["Name"]];
						}
					}

				$this->Disconnect();
			}
			else {
				$this->ErrorMessage ();
				$this->Disconnect();
			}			
		}
		
		$criterias[Type] = $this->Fields($criterias);		
		return $criterias;
	}

	public function ExecuteSearchProcedure ($procedureName, $scope, $Data) {
		$references = array();

		$sentence = $this->ExecuteProcedure ($procedureName, $scope, $Data, TRUE);
		if (!$sentence)
			return FALSE;

		$BD = $this->SelectDataBase($scope);
		if (!is_array($sentence)) {
			if (!$sentence)
				return FALSE;
			else
				$sql = $this->GetResult();
		}
		else {
			$sqlParams = "SELECT Name,Type FROM ".ParametersTable." WHERE UidProc = (SELECT Uid FROM ".ProceduresTable." WHERE Name='$procedureName') ORDER BY Orden ASC";
			if ($this->Connect($BD)) {
				$outcome = $this->SendQuery($sqlParams);
				if ($outcome) {			
					$parametersNumber = $this->RowsNumber($outcome);
					if ($parametersNumber > 0)
						while ($row = $this->ReadData ($outcome))
							$parameters[$row["Name"]] = $row["Type"];
	
					$outputParametersNumber = 0;
					$outputParameters = array();
					foreach ($parameters as $name => $type) {
						if (($type == Output)) {
							$outputParametersNumber++;
							$outputParameters[$outputParametersNumber] = $name;						
						}
					}
				}
			}
	


			$result = $sentence[$outputParameters[1]];
			$sql = $sentence[$outputParameters[2]];
			$tables = array_keys($sentence);
			foreach ($tables as $name)
				if (($name != $outputParameters[1]) && ($name != $outputParameters[2]))
					$references[$name] = $sentence[$name];
		}
		
		$columns = array();
		foreach ($references as $tableName){
			$columns = array_merge($columns,$this->ExternalKeys($tableName, $scope));
		}

		$columns = $this->ValuesList($columns);
//echo "CONS: $sql<br/>";
		if ($this->Connect($BD)) {		
			$outcome = $this->SendQuery($sql);

			if ($outcome) {			
				$outcomesnumber = $this->RowsNumber($outcome);
				$columnsNumber = $this->ColumnsNumber($outcome);

				$table = array();
				if ($outcomesnumber > 0) {
//					while ($this->ReadData ($outcome)) {
//						$row = array();
//						for ($i = 1; $i <= $columnsNumber; $i++) {
//							$columnName = $this->ColumnName($outcome, $i);
//							$columnValue = $this->GetField($outcome, $i);
//							if (isset($columns[$columnName]))
//								$row[$columnName] = $columns[$columnName][$columnValue];
//							else
//								$row[$columnName] = $columnValue;
					while ($resRow = $this->ReadData ($outcome, FALSE)) {
						$row = array();
						for ($i = 0; $i <= $columnsNumber - 1; $i++) {
							$columnName = $this->ColumnName($outcome, $i);							
							$columnValue = $resRow[$i];

							// TYPE BIT
							if (!ctype_print($resRow[$i]) && strlen ($resRow[$i]) == 1) {
								if ((int) ord ($resRow[$i]) == 0)
									$row[$columnName] = No;
								else
									$row[$columnName] = Yes;
							}
							else if (isset($columns[$columnName]) && $columnValue !== null) {
								$row[$columnName] = $columns[$columnName][$columnValue];
							}
							else
								$row[$columnName] = $columnValue;
						}
						$table[] = $row;
					}
				}
				$this->Disconnect();
				return $table;
			}
			else {
				$this->ErrorMessage ();
				$this->Disconnect();
			}
		}
		else
			$this->ErrorMessage();
		return FALSE;
	}


}

?>